﻿Imports System
Imports System.Data
Imports System.Data.SqlServerCe
Imports System.Reflection
Imports Ocean.OceanFramework.SQLCompactDataAccess.DataAccessConstants

Namespace SQLCompactDataAccess

    'If you cringe at the thought of using Reflection at runtime in a loop,
    '  please check out the performance numbers of this code, then start using it.
    'This code caches the reflected type and resuses it, so you only pay the cost once.
    '
    'http://karlshifflett.wordpress.com/2008/04/28/sample-series-bench-marking-object-loading-application-ii/
    Public Class ReflectionBuilder(Of T)

#Region " Declarations "

        Private _objBuilderProperties As PropertyInfo()

        '.NET guarantees thread safety for shared initialization
        Private Shared _objReflectionBuilderProperties As New Dictionary(Of Type, PropertyInfo())

#End Region

#Region " Constructors "

        Public Sub New()
        End Sub

#End Region

#Region " DataRow "

        Public Function Build(ByVal objRow As DataRow) As T

            If _objBuilderProperties Is Nothing Then
                CreateBuilder(objRow)
            End If

            Dim objReturnValue As T = DirectCast(Activator.CreateInstance(GetType(T)), T)

            'this method prevents any validation code from running during loading
            Dim mi As MethodInfo = GetType(T).GetMethod(G_STRING_BEGINLOADING)

            If mi IsNot Nothing Then
                mi.Invoke(objReturnValue, Nothing)
            End If

            For intX As Integer = 0 To objRow.Table.Columns.Count - 1

                If _objBuilderProperties(intX) IsNot Nothing AndAlso Not IsDBNull(objRow(intX)) Then
                    _objBuilderProperties(intX).SetValue(objReturnValue, objRow(intX), Nothing)
                End If

            Next

            'this sets the ActiveRuleSet property on the object to Update
            Dim prop As PropertyInfo = GetType(T).GetProperty(G_STRING_ACTIVERULESET)

            If prop IsNot Nothing Then
                prop.SetValue(objReturnValue, "Update", Nothing)
            End If

            'this method marks the object as not dirty and turns all the features back on
            mi = GetType(T).GetMethod(G_STRING_ENDLOADING)

            If mi IsNot Nothing Then
                mi.Invoke(objReturnValue, Nothing)
            End If

            Return objReturnValue
        End Function

        Private Sub CreateBuilder(ByVal objRow As DataRow)

            If _objReflectionBuilderProperties.TryGetValue(GetType(T), _objBuilderProperties) Then
                Exit Sub
            End If

            _objBuilderProperties = New PropertyInfo(objRow.Table.Columns.Count - 1) {}

            For intX As Integer = 0 To objRow.Table.Columns.Count - 1
                _objBuilderProperties(intX) = GetType(T).GetProperty(objRow.Table.Columns.Item(intX).ColumnName)
            Next

            _objReflectionBuilderProperties.Add(GetType(T), _objBuilderProperties)
        End Sub

#End Region

#Region " SqlDataReader Builder "

        Public Function Build(ByVal objReader As SqlCeDataReader) As T

            If _objBuilderProperties Is Nothing Then
                CreateBuilder(objReader)
            End If

            Dim objReturnValue As T = DirectCast(Activator.CreateInstance(GetType(T)), T)

            'this method prevents any validation code from running during loading
            Dim mi As MethodInfo = GetType(T).GetMethod(G_STRING_BEGINLOADING)

            If mi IsNot Nothing Then
                mi.Invoke(objReturnValue, Nothing)
            End If

            For intX As Integer = 0 To objReader.FieldCount - 1

                If _objBuilderProperties(intX) IsNot Nothing AndAlso Not objReader.IsDBNull(intX) Then
                    _objBuilderProperties(intX).SetValue(objReturnValue, objReader(intX), Nothing)
                End If

            Next

            'this sets the ActiveRuleSet property on the object to Update
            Dim prop As PropertyInfo = GetType(T).GetProperty(G_STRING_ACTIVERULESET)

            If prop IsNot Nothing Then
                prop.SetValue(objReturnValue, "Update", Nothing)
            End If

            'this method marks the object as not dirty and turns all the features back on
            mi = GetType(T).GetMethod(G_STRING_ENDLOADING)

            If mi IsNot Nothing Then
                mi.Invoke(objReturnValue, Nothing)
            End If

            Return objReturnValue
        End Function

        Private Sub CreateBuilder(ByVal objReader As SqlCeDataReader)

            If _objReflectionBuilderProperties.TryGetValue(GetType(T), _objBuilderProperties) Then
                Exit Sub
            End If

            _objBuilderProperties = New PropertyInfo(objReader.FieldCount - 1) {}

            For intX As Integer = 0 To objReader.FieldCount - 1
                _objBuilderProperties(intX) = GetType(T).GetProperty(objReader.GetName(intX))
            Next

            _objReflectionBuilderProperties.Add(GetType(T), _objBuilderProperties)
        End Sub

#End Region

    End Class

End Namespace
